package com.wmjsoft.plugins.nutzplugin.dao

import org.nutz.dao.Chain
import org.nutz.dao.Dao
import org.nutz.dao.QueryResult
import org.nutz.dao.Sqls
import org.nutz.dao.entity.annotation.Column
import org.nutz.dao.entity.annotation.Table
import org.nutz.dao.sql.Criteria
import org.nutz.dao.sql.Sql
import org.slf4j.LoggerFactory
import java.lang.Exception
import java.lang.reflect.Field
import java.util.*

/**
 * 如果我没有写注释，请提醒我
 * @program: Maternal
 * @description:
 * @author: Mr.Lee
 * @create: 2021-02-20 14:33
 */
class QueerSql(var dao: Dao) {
    val log = LoggerFactory.getLogger(this.javaClass)!!


    var cnd: Criteria? = null

    var selectString: StringBuilder? = null

    var joinSelectString: StringBuilder? = null

    var joinString: StringBuilder? = null

    var chain: Chain? = null

    var clazz: Class<*>? = null

    var dtoClazz: Class<*>? = null

    var oneStatus = false

    val pageNumber = 0

    val pageSize = 0


    fun update(): Int {
        if (cnd == null) {
            throw RuntimeException("修改前请先设置修改条件")
        }
        return dao.update(clazz, chain, cnd)
    }


    fun delete(): Int {

        if (cnd == null || cnd.toString() == "") {
            throw RuntimeException("修改前请先设置修改条件")
        }
        return dao.clear(clazz, cnd)
    }


    fun <DTO> oneExecute(clazz: Class<DTO>): DTO? {
        fromTableSql()
        oneStatus = true
        val sql = createSql(clazz)
        val ts = dao.execute(sql).result as List<DTO>
        return if (ts.isEmpty()) {
            null
        } else ts[0]
    }

    fun <DTO> listExecute(clazz: Class<DTO>): List<DTO>? {
        fromTableSql()
        val sql = createSql(clazz)
        return dao.execute(sql).getList(clazz)
    }


    fun <DTO> pageExecute(clazz: Class<DTO>, pageSize: Int, pageNumber: Int): QueryResult {
        dtoClazz = clazz
        val pager = dao.createPager(pageNumber, pageSize)
        fromTableSql()
        val sql = createSql(clazz)
        pager.recordCount = dao.count("($sql) as t")
        sql.setPager(pager)
        val list = dao.execute(sql).getList(clazz)
        return QueryResult(list, pager)
    }

    fun selectCount(clazz: Class<*>): Int {
        dtoClazz = clazz
        val pager = dao.createPager(pageNumber, pageSize)
        fromTableSql()
        val sql = createSql(clazz)
        return dao.count("($sql) as t")
    }



    private fun <DTO> createSql(clazz: Class<DTO>): Sql {
        val sql = Sqls.create(selectString.toString() + joinString.toString() + " \$condition").setCondition(cnd)
            .setCallback(Sqls.callback.entities())
        log.debug(sql.toString())
        sql.entity = dao.getEntity(clazz)
        return sql
    }


    private fun initSelectFiledByT() {
        try {
            val fields = clazz!!.declaredFields
            val supperFields = clazz!!.superclass.declaredFields
            var baseModelFields: Array<Field?>? = null
            if (clazz!!.superclass.name.indexOf("BaseTreeModel") > 0) {
                baseModelFields = clazz!!.superclass.superclass.declaredFields
            }
            val fields_result = ArrayList(Arrays.asList(*fields))
            fields_result.addAll(Arrays.asList(*supperFields))
            if (baseModelFields != null) {
                fields_result.addAll(baseModelFields.toList() as List<Field>)
            }
            for (field in fields_result) {
                if ("serialVersionUID" == field.name) {
                    continue
                }
                var fieldName: String? = ""
                if (field.getAnnotation(Column::class.java) != null) {
                    fieldName = field.getAnnotation(Column::class.java).value
                    if (fieldName.isBlank()) {
                        fieldName = field.name
                    }
                    fieldName += " as " + field.name
                } else {
                    fieldName = field.name
                }
                selectString!!.append(" " + getTableName(clazz) + "." + fieldName + ",")
            }
        } catch (e: Exception) {
            throw RuntimeException("初始化查询字段出现异常，请检查dto实体类是否正常")
        }
    }


    private fun  fromTableSql() {
        if (this.selectString!!.isBlank()) {
            initSelectFiledByT()
        }
        selectString!!.append(joinSelectString ?: "")
        selectString!!.deleteCharAt(selectString!!.lastIndexOf(","))
        selectString!!.append(" from " + getTableName(clazz) + " " + getTableName(clazz))
        selectString = StringBuilder("select ").append(selectString)
    }

    fun getTableName(clazz: Class<*>?): String {
        return try {
            val o = clazz!!.newInstance()
            val table = o.javaClass.getAnnotation(Table::class.java)
            table.value
        } catch (e: Exception) {
            throw RuntimeException("获取表名发生异常，请检查注解是否添加")
        }
    }

    fun addTableName(filed: String, vararg clazzs: Class<*>?): String {
        return if (clazzs.isEmpty()) {
            getTableName(clazz) + "." + filed
        } else {
            getTableName(clazzs[0]) + "." + filed
        }
    }

}